﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace fhe
{
  namespace math
  {
    public struct Vec2
    {
      public double X
      {
        get { return x; }
        set { x = value; }
      }

      double x;

      public double Y
      {
        get { return y; }
        set { y = value; }
      }

      double y;

      public double this[int i]
      {
        get
        {
          switch (i)
          {
            case 0: return x;
            case 1: return y;
            default: throw new Exception();
          }
        }
        set
        {
          switch (i)
          {
            case 0: x = value; break;
            case 1: y = value; break;
            default: throw new Exception();
          }
        }
      }

      public Vec2(double x, double y)
      {
        this.x = x;
        this.y = y;
      }

      public override string ToString()
      {
        return string.Format("Vec2({0},{1})", X.ToString(".00"), Y.ToString(".00"));
      }

      public static bool operator ==(Vec2 v1, Vec2 v2)
      {
        return Math.Abs(v1.x - v2.x) < 1e-5 && Math.Abs(v1.y - v2.y) < 1e-5;
      }

      public static bool operator !=(Vec2 v1, Vec2 v2)
      {
        return !(v1 == v2);
      }

      public override bool Equals(object obj)
      {
        return obj is Vec2 && this == (obj as Vec2?);
      }

      public override int GetHashCode()
      {
        return base.GetHashCode();
      }

      public static Vec2 operator -(Vec2 v)
      {
        return new Vec2(-v.x, -v.y);
      }

      public static Vec2 operator +(Vec2 v1, Vec2 v2)
      {
        return new Vec2(v1.x + v2.x, v1.y + v2.y);
      }

      public static Vec2 operator -(Vec2 v1, Vec2 v2)
      {
        return new Vec2(v1.x - v2.x, v1.y - v2.y);
      }

      public static Vec2 operator *(Vec2 v1, Vec2 v2)
      {
        return new Vec2(v1.x * v2.x, v1.y * v2.y);
      }

      public static Vec2 operator /(Vec2 v1, Vec2 v2)
      {
        return new Vec2(v1.x / v2.x, v1.y / v2.y);
      }

      public static Vec2 operator *(Vec2 v1, double d)
      {
        return new Vec2(v1.x * d, v1.y * d);
      }

      public static Vec2 operator /(Vec2 v1, double d)
      {
        return new Vec2(v1.x / d, v1.y / d);
      }

      public double SquaredLength()
      {
        return x * x + y * y;
      }

      public double Length()
      {
        return Math.Sqrt(SquaredLength());
      }

      public Vec2 Normalize()
      {
        return this / Length();
      }

      public double Dot(Vec2 v)
      {
        return x * v.x + y * v.y;
      }

      public Vec2 Project(Vec2 v)
      {
        return v * (Dot(v) / v.SquaredLength());
      }

      public double Cross(Vec2 v)
      {
        return x * v.y - y * v.x;
      }

      public Vec2 Perp()
      {
        return new Vec2(-y, x);
      }

      public static double DistToLine(Vec2 a, Vec2 b, Vec2 p)
      {
        return (p - a).Cross(b - a) / (b - a).Length();
      }
    }
  }
}